////
//
/// \file   ./src/statement_node.cpp
//
//  Copyright 2007, 2008 Chandler Carruth
//
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
//  use this file except in compliance with the License.  You may obtain a copy
//  of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
//  License for the specific language governing permissions and limitations
//  under the License.
//
////

#include <inc/parser/statement_node.hpp>

#include <string>

#include <boost/scoped_ptr.hpp>

#include <inc/parser/procedure_call_node.hpp>
#include <inc/parser/mutation_node.hpp>
#include <inc/parser/parse_tree_node.hpp>
#include <inc/parser/ws_parser.hpp>

namespace inc {
namespace parser {

using std::string;
using boost::scoped_ptr;

/// \brief  Constructor for statement node
/// \author Chandler Carruth
/// \date   2008.06.04

StatementNode::StatementNode()
    : break_statement( false ),
      finish_statement( false ),
      ws( new WSParser() )
{}

/// \brief  Parse a statement
/// \author Chandler Carruth
/// \date   2007.06.27
///
/// This parses out a statement by selecting from the two literal statements
/// "break" and "finish", a procedure call, and a mutation.

bool
StatementNode::parse( const iterator& first,
                      const iterator& last,
                      iterator& last_parsed )
{
  assert( get_text().empty() && !node && !break_statement && !finish_statement
          && "This node was parsed more than once!" );

  //  The easiest to parse expression are the literal "break" and "finish"
  //  control flow statements.
  if( distance(first, last) >= 5 && string(first, first + 5) == "break" )
  {
    if( ws->parse_eol_ws( first + 5, last, last_parsed ) )
    {
      break_statement = true;
      set_text( string( first, last_parsed ) );
      return true;
    }
  }
  if( distance(first, last) >= 6 && string(first, first + 6) == "finish" )
  {
    if( ws->parse_eol_ws( first + 6, last, last_parsed ) )
    {
      finish_statement = true;
      set_text( string( first, last_parsed ) );
      return true;
    }
  }

  //  We parse function calls next because all procedure calls begin with
  //  a valid name, but are followed by a () pair. Mutations may also begin
  //  with a name, but there won't be a non-space delimited () pair following
  //  it.
  boost::scoped_ptr<ParseTreeNode> proc( new ProcedureCallNode );
  if( proc->parse( first, last, last_parsed ) )
  {
    set_text( proc->get_text() );
    node.swap( proc );
    return true;
  }

  boost::scoped_ptr<ParseTreeNode> mutation( new MutationNode );
  if( mutation->parse( first, last, last_parsed ) )
  {
    set_text( mutation->get_text() );
    node.swap( mutation );
    return true;
  }

  last_parsed = first;
  return false;
}

/// \brief  Convenience getter for an procedure call sub-node
/// \author Chandler Carruth
/// \date   2008.05.24

ProcedureCallNode*
StatementNode::get_procedure_call() const
{
  return dynamic_cast<ProcedureCallNode*>( node.get() );
}

/// \brief  Convenience getter for an mutation sub-node
/// \author Chandler Carruth
/// \date   2008.05.24

MutationNode*
StatementNode::get_mutation() const
{
  return dynamic_cast<MutationNode*>( node.get() );
}

} //  end parser namespace
} //  end inc namespace
